package com.manolovn.trianglify.triangulator;

import com.manolovn.trianglify.domain.Point;
import com.manolovn.trianglify.domain.Edge;
import com.manolovn.trianglify.domain.Triangle;
import com.manolovn.trianglify.util.EdgeDistanceComparator;

import java.util.Arrays;
import java.util.Vector;

/**
 * Triangulation model
 */
public class Triangulation {
    private Vector<Triangle> triangleVector;

    /**
     * default constructor
     */
    public Triangulation() {
        this.triangleVector = new Vector<>();
    }

    /**
     * this method will used to add triangles
     */
    public void add(Triangle triangle) {
        this.triangleVector.add(triangle);
    }

    /**
     * to method will used to remove triangles
     */
    public void remove(Triangle triangle) {
        this.triangleVector.remove(triangle);
    }

    /**
     * to method will used to get all triangles
     */
    public Vector<Triangle> getTriangles() {
        return this.triangleVector;
    }

    /**
     * this method returns triangle if it contains point
     *
     * @param point refers to triangle point
     * @return Triangle if it contains point
     */
    public Triangle findContainingTriangle(Point point) {
        for (Triangle triangle : triangleVector) {
            if (triangle.contains(point)) {
                return triangle;
            }
        }
        return null;
    }

    /**
     * this method returns triangle having neighbour edge
     *
     * @param triangle is triangle we passed
     * @param edge refers to passed edge
     * @return Triangle having neighbour edge
     */
    public Triangle findNeighbour(Triangle triangle, Edge edge) {
        for (Triangle triangleFromSoup : triangleVector) {
            if (triangleFromSoup.isNeighbour(edge) && triangleFromSoup != triangle) {
                return triangleFromSoup;
            }
        }
        return null;
    }

    /**
     * this method returns triangle having neighbour edge
     *
     * @param edge refers to passed edge
     * @return Triangle having neighbour edge
     */
    public Triangle findOneTriangleSharing(Edge edge) {
        for (Triangle triangle : triangleVector) {
            if (triangle.isNeighbour(edge)) {
                return triangle;
            }
        }
        return null;
    }

    /**
     * this method is used to find nearest edge
     *
     * @param point refers to point passed
     * @return Edge will return nearest edge
     */
    public Edge findNearestEdge(Point point) {
        Vector<EdgeDistanceComparator> edgeVector = new Vector<>();

        for (Triangle triangle : triangleVector) {
            edgeVector.add(triangle.findNearestEdge(point));
        }

        EdgeDistanceComparator[] edgeDistancePacks = new EdgeDistanceComparator[edgeVector.size()];
        edgeVector.toArray(edgeDistancePacks);

        Arrays.sort(edgeDistancePacks);
        return edgeDistancePacks[0].edge;
    }

    /**
     * this method will removed used triangles
     *
     * @param vertex refers to point passed
     */
    public void removeTrianglesUsing(Point vertex) {
        Vector<Triangle> trianglesToBeRemoved = new Vector<>();

        for (Triangle triangle : triangleVector) {
            if (triangle.hasVertex(vertex)) {
                trianglesToBeRemoved.add(triangle);
            }
        }

        triangleVector.removeAll(trianglesToBeRemoved);
    }
}
